#pragma once

class CDataPacketReader
{
public:
	CDataPacketReader()
	{
		m_pMemory = m_pMemoryEnd = m_pOffset = m_pDataEnd = 0;
	}
	CDataPacketReader(void* lpDataPtr, size_t nSize)
	{
		m_pMemory = m_pOffset = (char*)lpDataPtr;
		m_pMemoryEnd = m_pDataEnd = m_pMemory + nSize;
	}

public:
	inline size_t getLength()
	{
		return m_pDataEnd - m_pMemory;
	}

	inline size_t getPosition()
	{
		return m_pOffset - m_pMemory;
	}

	inline size_t setPosition(size_t nPos)
	{
		size_t memSize = m_pMemoryEnd - m_pMemory;
		if (nPos > memSize)
			nPos = memSize;

		m_pOffset = m_pMemory + nPos;
		return nPos;
	}

	inline size_t getAvaliableLength()
	{
		return m_pDataEnd - m_pOffset;
	}
public:
	inline size_t readBuf(void* lpBuffer, size_t nSize)
	{
		size_t avaliableSize = m_pDataEnd - m_pOffset;
		
		if (nSize > avaliableSize)
			nSize = avaliableSize;

		if (nSize > 0)
		{
			memcpy(lpBuffer, m_pOffset, nSize);
			m_pOffset += nSize;
		}
		return nSize;
	}

	template <typename T>
	inline T readAtom()
	{
		T val;
		size_t avaliableSize = m_pDataEnd - m_pOffset;
		if (avaliableSize >= sizeof(T))
		{
			val = *(T*)m_pOffset;
			m_pOffset += sizeof(T);
		}
		else
		{
			memset(&val, 0, sizeof(T));
		}

		return val;
	}

	template <typename TS, typename TL>
	size_t rawReadStringLen(TS str, size_t nToRead)
	{
		size_t avaliableSize = m_pDataEnd - m_pOffset;
		if (avaliableSize < sizeof(TL))
		{
			return -1;
		}
		else
		{
			size_t realLen = readAtom<TL>();
			avaliableSize -= sizeof(TL);

			//
			if (realLen < nToRead)
				nToRead = realLen;

			if (nToRead > (avaliableSize/sizeof(*str)))
				nToRead = avaliableSize/sizeof(*str);

			//
			readBuf(str, nToRead*sizeof(*str));

			//jump 
			if (realLen > nToRead)
				m_pOffset += (realLen - nToRead) * sizeof(*str);
			
			return realLen;
		}		
	}

	inline size_t readString(char* pszString, size_t nToRead)
	{
		return rawReadStringLen<char*, unsigned short>(pszString, nToRead);
	}

	inline size_t readWString(wchar_t* pszString, size_t nToRead)
	{
		return rawReadStringLen<wchar_t*, unsigned short>(pszString, nToRead);
	}

protected:
	char* m_pMemory;
	char* m_pMemoryEnd;
	char* m_pOffset;
	char* m_pDataEnd;
};
